<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BRepository
 *
 * @author ID59C
 */
class BRepository3 {

    const New_Row = 'new_row';

    public $table = null;
    public $modelClass = null;
    public $findSql = null;
    public $entity = null;
    public $tableToModelMapList = array();
    public $entityToModelMapList = array();
    public $searchablePropertyList = array();
    /*
     * format for propertyToColumnMapList:
     * array('entityClass'=>array('property'=>'column','modelClass'=>'model)
     */
    protected $entityPropertyToColumnMapList = array();

    public function __construct($owner = NULL) {
        if ($owner instanceof BEntity)
            $this->entity = $owner;
        if (is_string($owner))
            $this->table = $owner;

        if ($owner instanceof CActiveRecord)
            $this->modelClass = $owner;
        else
            $this->modelClass = $this->populateModel($owner);
    }

    /**
     * 
     * @param type $data
     * @return \BRow
     */
    public function getRow($data = NULL, $autoLoad = TRUE, $model = NULL) {

        if (!$model instanceof CActiveRecord)
            $model = $this->getModel();

//$findContext = array();

        if ($model instanceof CActiveRecord) {

            /*
              if (isset($model->parent_id)) {
              //init tree row
              $count = $model->count();
              if ($count == 0) {
              $ar = new $model();
              $ar->attributes['name'] = 'root';
              $ar->save();
              }
              }
             * 
             */

            $row = new BRow();
            $row->setModel($model);
            //$row->setSearchableAttributes($this->propertyListToAttributeList($this->searchablePropertyList));
            if ($this->searchablePropertyList != NULL) {
                $searchableList = $this->propertyListToAttributeList($this->searchablePropertyList);
                $row->setSearchableAttributes($searchableList);
            }

            if ($data != self::New_Row) {
                if ($data == NULL) {
                    if ($this->entity instanceof BEntity) {
                        $data = $this->entity;
                    }
                }
                if ($data != NULL) {
                    $findAttributes = $this->populateFindContext($data);
                    $data = $this->populateAttributeList($data);
                }

                if ($autoLoad && $findAttributes != NULL) {
                    $row->load($data);
                } else {
                    $row->attributes += $data;
                }
            }

            return $row;
        }
    }

    /**
     * 
     * @param type $data
     * @return BRow
     */
    public function getNewRow($data = NULL, $model = NULL) {
        return $this->getRow(self::New_Row, $model);
    }

    public function getView($data = NULL) {
        $view = new BView();
        $view->setModel($this->getModel());
        if ($data == NULL)
            $data = $this->entity;
        $data = $this->populateAttributeList($data);
        $view->load($data);
        return $view;
    }

    public function getRoot($data = NULL) {
        $model = $this->getModel();
        if ($model instanceof CActiveRecord) {
            if (isset($model->parent_id)) {
                $count = $model->count();
                if ($count == 0) {
                    $ar = new $model();
                    $ar->attributes['name'] = 'root';
                    $ar->save();
                }
                $row = new BRow();
                $ar = $model->findByPk(1);
                $row->attributes = $ar->attributes;
                $row->setModel($model);
                return $row;
            }
        }
    }

    public function getModelClass($data = NULL) {
        return $this->modelClass;
    }

    /**
     * 
     * @param type $data
     * @return \CActiveRecord
     */
    public function getModel($data = NULL) {
        $modelClass = $this->modelClass;
        if (class_exists($modelClass))
            return new $modelClass();
    }

    public function getTableName($data = NULL) {
        $model = $this->getModel();

        if ($model instanceof CActiveRecord) {
            $tableSchema = $model->getTableSchema();
            return $tableSchema->name;
        }
    }

    public function setModel($model) {
        if (is_string($model))
            $this->modelClass = $model;
        if ($model instanceof CActiveRecord)
            $this->modelClass = get_class($model);
    }

    protected function populateModel($data) {
        if (is_string($data)) {
            $tableName = $data;
            if (isset($this->tableToModelMapList[$tableName]))
                return $this->tableToModelMapList[$tableName];
        }
        if ($data instanceof BEntity) {
            $entityClass = get_class($data);
            if (isset($this->entityToModelMapList[$entityClass]))
                return $this->entityToModelMapList[$entityClass];
            else { //return default model class for entity
                /* $firstLetter = substr($entityClass, 0, 1);
                  $pattern = "/" . '^' . $firstLetter . "/";
                  $replaceMent = $firstLetter . 'M';
                  $modelClass = preg_replace($pattern, $replaceMent, $entityClass);
                 * 
                 */
                $modelClass = 'M' . $entityClass;
                if (class_exists($modelClass, FALSE))
                    return $modelClass;
                else {
                    $firstLetter = substr($entityClass, 0, 1);
                    $modelClass = str_replace($firstLetter, $firstLetter . 'M', $entityClass);
                    if (class_exists($modelClass, FALSE))
                        return $modelClass;
                }
                return $modelClass;
            }
        }
    }

    public function addTableToModelMap($tableName, $model, $data = NULL) {
        if ($model instanceof CActiveRecord)
            $modelClass = get_class($model);
        if (is_string($model))
            $modelClass = $model;

        $this->tableToModelMapList[$tableName] = get_class($modelClass);
    }

    public function addEntityToModelMap($entity, $model, $data = NULL) {
        if ($entity instanceof BEntity)
            $entityClass = get_class($entity);
        if (is_string($entity))
            $entityClass = $entity;
        if ($model instanceof CActiveRecord)
            $modelClass = get_class($model);
        if (is_string($model))
            $modelClass = $model;
        $this->entityToModelMapList[$entityClass] = $modelClass;
    }

    public function addPropertyToColumnMap($property, $column, $entity = NULL) {
        if (!$entity instanceof BEntity)
            $entity = $this->entity;

        if ($entity instanceof BEntity) {
            $entityClass = get_class($entity);
            $mapList = array();
            if (isset($this->entityPropertyToColumnMapList[$entityClass])) {
                $mapList = $this->entityPropertyToColumnMapList[$entityClass];
            }
            $propertyList = $entity->getPropertyList();
            if (in_array($property, array_keys($propertyList))) {
                $mapList[$property] = $column;
                $this->entityPropertyToColumnMapList[$entityClass] = $mapList;
            }
        }
    }

    public function getPropertyToColumnMapList($entity = null) {
        if (!$entity instanceof BEntity)
            $entity = $this->entity;

        $mapList = array();

        if ($entity instanceof BEntity) {
            $entityClass = get_class($entity);
            if (isset($this->entityPropertyToColumnMapList[$entityClass]))
                $mapList = $this->entityPropertyToColumnMapList[$entityClass];
        }

        return $mapList;
    }

    public function populateFindContext($data = null, $entity = NULL) {
        if ($entity == NULL)
            $entity = $this->entity;

        if ($data == NULL)
            $data = $entity;

        if (is_numeric($data) && $data > 0) {
            return $data;
        }

        if (is_string($data)) {
            $name = $data;
            $data = array();
            $data['name'] = $name;
        }

        if ($data instanceof BEntity) {
            //if ($data->getId() != NULL && $data->getId() > 0)
            //return $data->getId();
            $data = $data->getPropertyList();
        }
        if (is_array($data)) {
            if (isset($data['sql']))
                return $data;

            /*
              if ($entity instanceof BEntity) {
              $entityData = $entity->getPropertyList();
              $entityData2 = array();
              foreach ($entityData as $name => $value) {
              if ((is_numeric($value) || is_string($value)) && $value != NULL)
              $entityData2[$name] = $value;
              }
              $data += $entityData2;
              }
             * 
             */

            $row = $this->getNewRow();
            $searchableAttributes = $row->getSearchableAttributes();
            $searchableAttributes += $this->searchablePropertyList;

            $findAttributes = array();

            $mapList = $this->getPropertyToColumnMapList($entity);
            foreach ($data as $name => $value) {
                if (!is_null($value)) {
                    if (isset($mapList[$name])) {
                        $col = $mapList[$name];
                        $findAttributes[$col] = $value;
                    }
                    if (in_array($name, $mapList)) {
                        $findAttributes[$name] = $value;
                    }
                }
            }

            if ($searchableAttributes != NULL) {
                $attributes = $findAttributes;
                $findAttributes = array();
                foreach ($searchableAttributes as $col) {
                    if (isset($attributes[$col]) && $attributes[$col] != NULL)
                        $findAttributes[$col] = $attributes[$col];
                }
            }

            return $findAttributes;
        }
    }

    public function populateAttributeList($data = NULL, $entity = NULL) {
        if ($entity == NULL)
            $entity = $this->entity;

        if ($data == NULL)
            $data = $entity;

        if (is_numeric($data) && $data > 0) {
            return $data;
        }

        if (is_string($data)) {
            $name = $data;
            $data = array();
            $data['name'] = $name;
        }

        if ($data instanceof BEntity) {
            //if ($data->getId() != NULL && $data->getId() > 0)
            //return $data->getId();
            $data = $data->getPropertyList();
        }
        if (is_array($data)) {
            if (isset($data['sql']))
                return $data;
            $row = $this->getNewRow();


            /*
              if ($entity instanceof BEntity) {
              $entityData = $entity->getPropertyList();
              $entityData2 = array();
              foreach ($entityData as $name => $value) {
              if ((is_numeric($value) || is_string($value)) && $value != NULL)
              $entityData2[$name] = $value;
              }
              $data += $entityData2;
              }
             * 
             */

            $findAttributes = array();

            $mapList = $this->getPropertyToColumnMapList($entity);
            foreach ($data as $name => $value) {
                if (!is_null($value)) {
                    if (isset($mapList[$name])) {
                        $col = $mapList[$name];
                        $findAttributes[$col] = $value;
                    }
                    if (in_array($name, $mapList)) {
                        $findAttributes[$name] = $value;
                    }
                }
            }

            foreach ($findAttributes as $name => $value) {
                if (!is_string($value) && !is_numeric($value))
                    $findAttributes[$name] = serialize($value);
            }

            return $findAttributes;
        }
    }

    public function loadEntity($data = NULL, &$entity = NULL) {
        if ($entity == NULL)
            $entity = $this->entity;

        $row = new BRow();

        if ($entity instanceof BEntity) {
            $modelClass = $entity->getRepository()->getModelClass();
            $row->setModel($modelClass);
        }

        if (is_numeric($data) && $data > 0) {
            $row->load($data);
        } else if (!$data instanceof BRow) {
            $findContext = $this->populateAttributeList($data, $entity);
            if ($findContext != NULL || !empty($findContext)) {
                $row = $this->getRow($findContext);
            }
        } else {
            $row = $data;
        }
//}

        if ($row instanceof BRow) {
            $attributes = $row->getAttributes();
            $propertyList = $this->attributeListToPropertyList($attributes);
            $entity->loadData($propertyList);
        }
    }

    public function saveEntity($data = array(), &$entity = NULL) {
        if ($entity == NULL)
            $entity = $this->entity;

        $propertyList = $entity->getPropertyList();
        if (is_array($data))
            $propertyList = $propertyList + $data;

        $attributes = $this->propertyListToAttributeList($propertyList);

        if ($entity->getId() != NULL) {
            $model = $this->populateModel($entity);
            $row = $this->getRow($entity->getId(), $model);
        } else {
            $row = new BRow();
            $model = $this->modelClass;
            $row->setModel($model);
        }
        $row->attributes = $attributes;
        if ($this->searchablePropertyList != NULL) {
            $row->searchableAttributes = $this->propertyListToAttributeList($this->searchablePropertyList);
        }
        $row->save();

        $propertyList = $this->attributeListToPropertyList($row->attributes);
        $entity->loadData($propertyList);
        return $entity;
    }

    public function propertyListToAttributeList($propertyList, $mapList = array()) {

        $attributes = array();

        if (empty($mapList)) {
            $mapList = $this->getPropertyToColumnMapList();
        }

        foreach ($propertyList as $name => $value) {
            if ($value != NULL) {
                if (isset($mapList[$name])) {
                    $col = $mapList[$name];
                    $attributes[$col] = $value;
                }
            }
        }

        return $attributes;
    }

    public function attributeListToPropertyList($attributeList, $mapList = array()) {
        $properties = array();

        if (empty($mapList)) {
            $mapList = $this->getPropertyToColumnMapList();
        }

        foreach ($mapList as $property => $col) {
            if (isset($attributeList[$col]) && $attributeList[$col] != NULL) {
                $properties[$property] = $attributeList[$col];
            }
        }

        return $properties;
    }

    public function getCount($data = NULL) {
        if ($data == NULL) {
            $model = $this->getModel();
            return $model->count();
        }
        if (is_array($data)) {
            if (isset($data['sql'])) {
                $model = $this->getModel();
                $connection = $model->getDbConnection();
                if ($connection == NULL)
                    $connection = Blyn::app()->getActiveApp()->getDbAdapter()->getDbConnection();

                $sql = $data['sql'];
                //$condition = isset($data['condition']) ? $data['condition'] : NULL;
                $params = isset($data['params']) ? $data['params'] : array();
                $command = $connection->createCommand($sql);
                $count = $command->queryScalar();
                return $count;
            } else {
                $attributeList = $this->populateAttributeList($data);
                $model = $this->getModel();
                if (isset($data['model'])) {
                    $model = $data['model'];
                    unset($data['model']);
                    if (is_string($model))
                        $model = new $model();
                }
                $condition = '';
                if (isset($data['condition'])) {
                    $condition = $data['condition'];
                    unset($data['condition']);
                }
                $params = array();
                if (isset($data['params'])) {
                    $params = $data['params'];
                    unset($data['params']);
                }
                if ($model instanceof CActiveRecord) {
                    $count = $model->countByAttributes($attributeList, $condition, $params);

                    return $count;
                }
            }
        }

        return FALSE;
    }

    public function addSearchablePropertyList($propertyName, $colName = NULL) {
        $list = $this->getPropertyToColumnMapList();
        if ($colName == NULL) {
            if (isset($list[$propertyName]) && $list[$propertyName] != NULL)
                $colName = $list[$propertyName];
        }
        $this->searchablePropertyList[$propertyName] = $colName;
    }

    public function executeSql($sql, $params = NULL) {
        $model = $this->getModel();
        $connection = $model->getDbConnection();

        if ($sql != NULL) {
            $command = $connection->createCommand($sql);
            if($params!=NULL)
                return $command->execute($params);
            else {
                return $command->execute();
            }
        }
        return FALSE;
    }

}

?>
